<template>
  <body class="upload-body">
  <div class="editor-container">
    <!-- 使用 flex 容器包裹表单和按钮 -->
    <div class="form-and-buttons-container">
      <el-form
          ref="ruleFormRef"
          style="flex: 1"
          :model="form"
          :rules="rules"
          label-width="auto"
          class="demo-ruleForm"
          status-icon
      >
        <el-form-item prop="title" style="width: 100%;">
          <el-input v-model="form.title" placeholder="请输入标题" style="height: 50px;"/>
        </el-form-item>
        <el-form-item style="width: 100%;">
          <textarea v-model="form.description" class="input-body" style="height:40vh; position: relative;"
                    placeholder="请在这里输入正文"></textarea>
        </el-form-item>
        <el-form-item label="档案类型：" style="width: 100%;">
          <el-select
              v-model="form.channels"
              multiple
              placeholder="Select"
              style="width: 240px"
          >
            <el-option
                v-for="item in options"
                :key="item.id"
                :label="item.name"
                :value="item.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="发布时间：" style="width: 100%;">
          <el-date-picker
              v-model="form.publishDate"
              type="datetime"
              placeholder="请输入发布时间"
              value-format="YYYY-MM-DD HH:mm:ss"
          />
        </el-form-item>
        <el-form-item>
          <el-upload
              v-model:file-list="images"
              action="/api/api/files/upload"
              list-type="picture-card"
              :on-preview="handlePictureCardPreview"
              :on-remove="handleRemove"
              :headers="{'Authorization':token}"
          >
            <el-icon>
              <Plus/>
            </el-icon>
          </el-upload>

          <el-dialog v-model="dialogVisible">
            <img w-full :src="dialogImageUrl" alt="Preview Image"/>
          </el-dialog>
        </el-form-item>
        <el-form-item>
          <div class="editor-options">
            <el-dropdown>
              <el-button type="primary">
                发布类型
                <el-icon class="el-icon--right">
                  <arrow-down/>
                </el-icon>
              </el-button>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item @click="filesSubmit()">发布</el-dropdown-item>
                  <el-dropdown-item @click="filesSubmit(3)">草稿</el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>

          </div>
        </el-form-item>
      </el-form>

      <!-- 辅助组件 -->
      <div class="button-container">
        <el-button type="primary" @click="voice()" style="background-color: slateblue;">语言转文字</el-button>
        <el-button type="primary" @click="camera()" style="background-color: slateblue">实时摄像记录</el-button>
      </div>
    </div>
    <el-drawer v-model="drawer1" :direction="'ltr'" title="I am the title" :with-header="false" size="50%">
      <div style="display: flex;justify-content: center;align-items: center;">
        <div style="border: 1px solid black;width: 1200px;height: 350px;
                    border-radius: 10px 10px 10px 10px;background:azure;" v-text="form.speechDescritpion.join(',')">
        </div>
      </div>
      <div style="display: flex;justify-content: center;margin-right: 50px">
        <div class="body-speech">
          <el-button type="success" @click="eanble()">开启录音</el-button>
        </div>
        <div style="width: 100px;" class="body-speech">
          <el-button type="success" @click="downUp()">关闭录音</el-button>
        </div>
        <div style="width: 100px;">
          <el-button type="success" @click="clearText()">清空文本内容</el-button>
        </div>
      </div>
    </el-drawer>
    <el-drawer v-model="drawer2" :direction="'ltr'" title="I am the title" :with-header="false" size="50%">
      <div class="container">
        <canvas ref="canvas" width="640" height="360"></canvas>
        <video ref="video" autoplay loop muted></video>
        <div class="button-group">
          <el-button type="success" @click="startRecording">开始录制</el-button>
          <el-button type="danger" @click="stopRecording" :disabled="!isRecording">结束录制</el-button>
        </div>
      </div>
    </el-drawer>
  </div>
  </body>
</template>

<script setup>
import {nextTick, onBeforeUnmount, onMounted, onUnmounted, onUpdated, ref, watch} from "vue";
import {ElMessage} from "element-plus";
import {enableJs, shutdownJs} from "../api/speech/speech.js";
import axios from "axios";
import {filesSaveJs} from "../api/files/files.js";
import {channelListJs} from "../api/channel/channel.js";


const ruleFormRef = ref()
const drawer1 = ref(false)  // 语音转换
const drawer2 = ref(false)  // 实时摄像记录
// 获取token
const token = localStorage.getItem("token")
const images = ref([])


// 上传所使用表单
const form = ref({
  title: null,
  description: null,  // 基本描述内容
  status: null,
  publishDate: null,
  imageUrl:[],
  speechDescritpion: [],  // 语音录入所需要的字符串数组
  vedioImg: null,
  channels:[]  // 类型集合id
})
// 校验
const rules = ref({
  title: [
    {required: true, message: '标题不能为空', trigger: 'blur'},
    {min: 3, message: '标题最少需要3个字符', trigger: 'blur'},
  ],
})

// 语音转换文字
function voice(){
  drawer1.value = true
}
// 定义数组
// WebSocket 实例
const socket = ref(null);
// 存储 WebSocket 消息
const messages = ref([]);

// 创建 WebSocket 连接
const connectWebSocket = () => {
  socket.value = new WebSocket('ws://localhost:8081/websocket');

  // WebSocket 打开连接时
  socket.value.onopen = () => {
    console.log('WebSocket 连接已打开');
  };

  // WebSocket 接收到消息时
  socket.value.onmessage = (event) => {
    console.log('收到消息:', event.data);
    messages.value.push(event.data);
    form.value.speechDescritpion.push(event.data)  // 接受语音转换文字数据
  };

  // WebSocket 错误时
  socket.value.onerror = (error) => {
    console.error('WebSocket 错误:', error);
  };

  // WebSocket 连接关闭时
  socket.value.onclose = () => {
    console.log('WebSocket 连接已关闭');
  };
};
// 组件卸载时关闭 WebSocket 连接
onBeforeUnmount(() => {
  if (socket.value) {
    socket.value.close();
  }
});

// 开启语音录制
function eanble() {
  // 点击之后开启websocket连接
  connectWebSocket();
  enableJs()
  ElMessage.success("开启成功")
}

// 关闭录音
function downUp() {
  shutdownJs()
  ElMessage.success("关闭成功")
}

// 清空文本内容
function clearText() {
  form.value.speechDescritpion = []
}


const dialogImageUrl = ref('')
const dialogVisible = ref(false)

const handleRemove = (uploadFile, uploadFiles) => {
  console.log(uploadFile, uploadFiles)
}

const handlePictureCardPreview = (uploadFile) => {
  dialogImageUrl.value = uploadFile.url
  dialogVisible.value = true
}

// 摄像头
// 定义响应式数据
const canvas = ref(null);
const video = ref(null);
const isRecording = ref(false);
const canRecord = ref(false);
const chunks = ref([]);

let frameId = null;
let recorder = null;
// 新增变量用于记录录制器的状态（'recording' 录制中，'paused' 暂停中，'stopped' 停止）
const recorderState = ref('stopped');

let videoWidth = 848;
let videoHeight = 480;
const frameRate = 24; // 调整帧率
const encodeType = "video/webm;codecs=opus"; // 尝试使用不同的编码格式

// 绘制帧的函数
const drawFrame = () => {
  const canvasContext = canvas.value.getContext("2d");
  canvasContext.drawImage(video.value, 0, 0, videoWidth, videoHeight);
  frameId = requestAnimationFrame(drawFrame);
};

// 开始录制的函数
const startRecording = () => {
  isRecording.value = true;
  canRecord.value = false;
  recorderState.value = 'recording';

  // 清空之前的录制数据
  chunks.value = [];

  // 请求音频权限
  navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true
  }).then(mediaStream => {
    video.value.srcObject = mediaStream;
    video.value.play();

    // 获取视频流的实际尺寸
    video.value.addEventListener('loadedmetadata', () => {
      videoWidth = video.value.videoWidth;
      videoHeight = video.value.videoHeight;
      canvas.value.width = videoWidth;
      canvas.value.height = videoHeight;

      // 创建一个新的媒体流，包含视频和音频轨道
      const combinedStream = new MediaStream([...mediaStream.getTracks(), ...canvas.value.captureStream(frameRate).getTracks()]);
      recorder = new MediaRecorder(combinedStream, {
        mimeType: encodeType
      });

      recorder.ondataavailable = e => {
        chunks.value.push(e.data);
      };

      recorder.start(10);
      drawFrame();
    });
  }).catch(error => {
    alert("打开摄像头或麦克风失败");
    isRecording.value = false;
    canRecord.value = true;
    recorderState.value = 'stopped';
  });
};

// 停止录制的函数
const stopRecording = () => {
  isRecording.value = false;
  canRecord.value = true;
  recorderState.value = 'stopped';
  if (recorder) {
    recorder.stop();
  }
  cancelAnimationFrame(frameId);
  download();

  // 重置状态变量
  chunks.value = [];
  frameId = null;
  recorder = null;

  // 停止媒体流
  if (video.value && video.value.srcObject) {
    const tracks = video.value.srcObject.getTracks();
    tracks.forEach(track => track.stop());
    video.value.srcObject = null;
  }
};

// 下载函数
const download = async () => {
  const blob = new Blob(chunks.value, {type: encodeType});
  const fileName = new Date().getTime() + ".webm";
  // 创建FormData对象，用于上传文件
  const formData = new FormData();
  formData.append('video', blob, fileName);
  form.value.vedioImg = formData
  try {
    const token = localStorage.getItem("token");
    // 发送POST请求到后端接口，这里假设后端接口地址是'/api/uploadVideo'，根据实际情况调整
    const response = await axios.post('/api/api/upload', formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
        ' Authorization': `Bearer ${token}`,
      }
    });
    console.log('视频文件已成功发送到后端，后端返回信息：', response.data);
  } catch (error) {
    console.error('发送视频文件到后端出错：', error);
  }
};


// 抽屉摄像头打开
function camera() {
  drawer2.value = true
  navigator.mediaDevices.getUserMedia({
    audio: false,
    video: true
  }).then(mediaStream => {
    nextTick(() => {
      if (video.value) { // 确保 video 元素已经被渲染
        video.value.srcObject = mediaStream;
        video.value.play();
      } else {
        console.error('Video element not found');
        ElMessage.error('视频元素未找到');
      }
    });
  }).catch(error => {
    console.error('打开摄像头失败，具体错误信息：', error);
    ElMessage.error('打开摄像头失败');
  });
}
// 组件卸载时执行的逻辑
onUnmounted(() => {
  if (recorder && recorder.state !== 'inactive') {
    recorder.stop();
  }
  if (video.value && video.value.srcObject) {
    const tracks = video.value.srcObject.getTracks();
    tracks.forEach(track => track.stop());
    video.value.srcObject = null;
  }
});
// 对外暴露的数据和方法
defineExpose({
  canvas,
  video,
  isRecording,
  canRecord,
  startRecording,
  stopRecording,
  recorderState,
});
const options = ref([])
// 档案类型查询
function channes(){
  channelListJs().then(res=>{
    if(res.data.code == 200){
      options.value = res.data.data
    }
  })
}
channes()


// 上传档案
function filesSubmit(val) {
  // 处理图片
  images.value.forEach(el=>{
    form.value.imageUrl.push(el.name)
  })
  if(val == null){
    // 正常发布状态
    filesSaveJs(form.value).then(res=>{
      if(res.data.code == 200){
        ElMessage.success("添加成功")
        form.value = ref({})
        images.value = []
        channes()
      }else{
        ElMessage.error("添加失败")
      }
    })
  }else {
    // 草稿状态
    form.value.status = val
    filesSaveJs(form.value).then(res=>{
      if(res.data.code == 200){
        ElMessage.success("添加成功")
        form.value = ref({})
        images.value = []
        channes()
      }else{
        ElMessage.error("添加失败")
      }
    })
  }

}


</script>
<style>
upload-body {
  font-family: Arial, sans-serif;
  background-color: #f4f4f4;
  height: 70vh;
}

.editor-container {
  width: 80%;
  height: 85vh;
  margin: auto;
  background-color: white;
  padding: 20px;
  border-radius: 5px;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
}

.input-title,
.input-body {
  width: 100%;
  padding: 10px;
  margin-bottom: 10px;
  border: 1px solid #ccc;
  border-radius: 3px;
}


.form-and-buttons-container {
  display: flex;
  align-items: flex-start; /* 确保子元素顶部对齐 */
  gap: 16px; /* 设置表单和按钮之间的间距 */
}

.button-container {
  display: flex;
  flex-direction: column; /* 垂直排列按钮 */
  align-items: flex-start; /* 左对齐按钮 */
  gap: 8px; /* 设置按钮之间的间距 */
}


.body-speech {
  width: 100px;
  margin-right: 40px;
}

canvas {
  display: none;
}

video {
  width: 848px;
  height: 480px;
  background: darkblue;
  display: block;
  border-radius: 2px;
  box-shadow: 0 1px 1.5px 1px rgba(0, 0, 0, 0.12);
  margin-top: -250px;
}

.button-group {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 50px;
  padding: 0 10px;
  width: 600px;
  height: 60px;
}

button {
  width: 150px;
  height: 60px;
  box-sizing: border-box;
  border: none;
  outline: none;
  border-radius: 2px;
  box-shadow: 0 1px 1.5px 1px rgba(0, 0, 0, 0.12);
  user-select: none;
}


button:last-child[disabled] {
  background: gray;
}

.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 80vh;
}

canvas {
  border: 2px solid #ccc;
  background-color: #fff;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  transition: transform 0.2s ease-in-out;
  margin-top: 60px; /* Adjust based on controls height */
  width: 100%;
  max-width: 800px;
  height: calc(100vh - 80px); /* Full height minus control panel height */
}

canvas:hover {
  transform: scale(1.02);
}

@media (max-width: 768px) {
  #controls {
    grid-template-columns: 1fr;
    width: 95%;
  }

  .control-group {
    flex-direction: column;
    align-items: flex-start;
  }

  .control-label {
    margin-bottom: 5px;
    margin-right: 0;
  }

  .control-button {
    margin-left: 0;
  }

  canvas {
    height: calc(100vh - 100px); /* Adjust for smaller screens */
  }
}

</style>